/*
 Copyright (C) 2009 are of bakabt
 boxtorrents, azureus, vuze, and java are copyrighted to their respective owner.

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; version 2 of the License.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */
package com.boxtorrents.azureus.action;

import java.util.HashSet;
import java.util.Set;

import org.gudy.azureus2.plugins.PluginConfig;
import org.gudy.azureus2.plugins.PluginConfigListener;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.PluginListener;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.download.DownloadPeerListener;
import org.gudy.azureus2.plugins.logging.LoggerChannel;
import org.gudy.azureus2.plugins.peers.Peer;
import org.gudy.azureus2.plugins.peers.PeerEvent;
import org.gudy.azureus2.plugins.peers.PeerListener2;
import org.gudy.azureus2.plugins.peers.PeerManager;
import org.gudy.azureus2.plugins.peers.PeerManagerEvent;
import org.gudy.azureus2.plugins.peers.PeerManagerListener2;
import org.gudy.azureus2.plugins.ui.config.BooleanParameter;
import org.gudy.azureus2.plugins.ui.config.StringParameter;
import org.gudy.azureus2.plugins.ui.model.BasicPluginConfigModel;

import com.boxtorrents.azureus.BoxTorrentsPlugin;
import com.boxtorrents.azureus.PluginParamConstants;

/**
 * @author are of bakabt.com
 */
public class ClientFilter implements PluginParamConstants {
	private static final long serialVersionUID = 5183368897928723813L;
	private static final String defaultBanList = "Xunlei,Transmission 0.[0-6]";
	private static Set<String> banned = new HashSet<String>();
	private static PluginInterface pi = BoxTorrentsPlugin.getPluginInterface();
	private static String[] bad;
	private static LoggerChannel log = BoxTorrentsPlugin.getLog();
	private static boolean noBadSeed = true;
	private static boolean enable = true;
	private static boolean notify = false;

	/**
	 * 
	 */
	public ClientFilter() {
		BasicPluginConfigModel model = pi.getUIManager()
		    .createBasicPluginConfigModel(pi.getPluginID(), "clientfilter");
		model.addLabelParameter2("config.clientfilter.title");
		BooleanParameter pEnable = model.addBooleanParameter2(
		    PR_CLIENTFILTER_ENABLE, "config.clientfilter.enable", true);
		StringParameter pBadList = model.addStringParameter2(PR_CLIENTFILTER_LIST,
		    "config.clientfilter.list", defaultBanList);
		model.addLabelParameter2("config.clientfilter.listdesc");
		BooleanParameter pNoBadSeed = model.addBooleanParameter2(
		    PR_CLIENTFILTER_SEED, "config.clientfilter.nobadseed", true);
		BooleanParameter pNotify = model.addBooleanParameter2(
		    PR_CLIENTFILTER_NOTIFY, "config.clientfilter.notify", false);
		pEnable.addEnabledOnSelection(pBadList);
		pEnable.addEnabledOnSelection(pNoBadSeed);
		pEnable.addEnabledOnSelection(pNotify);

		readConfig();
		pi.getPluginconfig().addListener(new PluginConfigListener() {
			public void configSaved() {
				readConfig();
			}
		});
		pi.getDownloadManager().getGlobalDownloadEventNotifier().addPeerListener(
		    new DownloadPeerListener() {
			    public void peerManagerAdded(final Download d, PeerManager pm) {
				    pm.addListener(new PeerManagerListener2() {
					    public void eventOccurred(final PeerManagerEvent e) {
						    final Peer peer = e.getPeer();
						    PeerListener2 listener2 = new PeerListener2() {
							    public void eventOccurred(PeerEvent e2) {
								    if (enable && e2.getType() == PeerEvent.ET_STATE_CHANGED
								        && peer != null && peer.getState() == Peer.TRANSFERING
								        && isBadClient(peer)) {
									    banClient(e.getPeerManager(), peer, d);
								    }
							    }
						    };
						    if (e.getType() == PeerManagerEvent.ET_PEER_ADDED) {
							    peer.addListener(listener2);
						    } else if (e.getType() == PeerManagerEvent.ET_PEER_REMOVED) {
							    peer.removeListener(listener2);
						    }
					    }
				    });
			    }

			    public void peerManagerRemoved(Download arg0, PeerManager arg1) {}
		    });
		pi.addListener(new PluginListener() {
			public void closedownComplete() {}

			public void closedownInitiated() {
				for (String s : banned) {
					pi.getIPFilter().unban(s);
				}
			}

			public void initializationComplete() {}
		});
	}

	private void readConfig() {
		PluginConfig pConfig = pi.getPluginconfig();
		String badClients = pConfig.getPluginStringParameter(PR_CLIENTFILTER_LIST,
		    defaultBanList);
		bad = badClients.split(",");
		for (int i = 0; i < bad.length; i++) {
			bad[i] = bad[i].trim().toLowerCase();
		}
		noBadSeed = pConfig.getPluginBooleanParameter(PR_CLIENTFILTER_SEED, true);
		enable = pConfig.getPluginBooleanParameter(PR_CLIENTFILTER_ENABLE, true);
		notify = pConfig.getPluginBooleanParameter(PR_CLIENTFILTER_NOTIFY, false);
	}

	private static boolean isBadClient(Peer peer) {
		if (peer == null || peer.getClient() == null || peer.getClient().equals(""))
		  return false;
		if (noBadSeed && peer.isSeed()) return false;
		final String client = peer.getClient().trim().toLowerCase();
		for (String s : bad) {
			if (s.equals("")) continue;
			if (client.matches(".*" + s + ".*")) {
				return true;
			}
		}
		return false;
	}

	private static void banClient(PeerManager pm, Peer peer, Download d) {
		if (notify) log.logAlert(LoggerChannel.LT_INFORMATION, "Banning "
		    + peer.getIp() + " bad client [" + peer.getClient() + "] on " + d.getName());
		else log.log(LoggerChannel.LT_INFORMATION, "Banning " + peer.getIp()
		    + " bad client [" + peer.getClient() + "] on " + d.getName());
		banned.add(peer.getIp());
		pm.removePeer(peer);
		pi.getIPFilter().ban(peer.getIp(), "bad client [" + peer.getClient() + "] on " + d.getName());
	}
}
